import http from '@ohos.net.http';
import { Resource } from 'GlobalResource';
import Logger from './Logger';

const HTTP_READ_TIMEOUT: number = 60000;
const CONTENT_TYPE_JSON: string = 'application/json; charset=utf-8';
const ACCESS_TOKEN_KEY: string = 'access_token';
const HTTP_UTIL: string = 'HttpUtil';

/**
 * HTTP 请求结果状态枚举
 */
export enum HttpResponseState {
  /**
   * 没有执行请求
   */
  NONE = 'none',

  /**
   * 请求成功
   */
  SUCCESS = 'success',

  /**
   * 请求失败
   */
  FAIL = 'fail'
}

/**
 * 自定义HTTP REQUEST 请求结果类型.
 */
export class HttResponseResult {
  /**
   * Code returned by the network request: success, fail.
   */
  code: HttpResponseState;

  /**
   * Server status code.
   */
  responseCode: http.ResponseCode | number;

  /**
   * Message returned by the network request.
   */
  message: string | Resource | null;

  /**
   * Data returned by the network request.
   */
  data: any;

  constructor() {
    this.code = HttpResponseState.NONE;
    this.responseCode = 0;
    this.message = null;
    this.data = null;
  }
}

/**
 * 封装 HttpRequest.
 * 需要申请 ohos.permission.INTERNET 权限。
 *
 * request接口开发步骤：
 *  1. 导入http命名空间：import http from '@ohos.net.http'。
 *  2. 调用 http.createHttp() 方法，创建一个HttpRequest对象。
 *  3. 调用HttpRequest对象的on()方法，订阅http响应头事件，此接口会比request请求先返回。可以根据业务需要订阅此消息。
 *  4. 调用HttpRequest对象的request()方法，传入http请求的url地址和可选参数，发起网络请求。
 *  5. 按照实际业务需要，解析返回结果。
 *  6. 调用HttpRequest对象的off()方法，取消订阅http响应头事件。
 *  7. 当该请求使用完毕时，调用HttpRequest对象的destroy()方法主动销毁。
 *
 * @param url URL for initiating an HTTP request
 * @param method Request method.
 * @param extraData Additional data of the request.
 * @returns Returns {@link ResponseResult}.
 */
export function httpRequest(url: string, method: http.RequestMethod, params?: any): Promise<HttResponseResult> {
  // 1.创建一个HTTP请求，里面包括发起请求、中断请求、订阅/取消订阅HTTP Response Header事件(request、destroy、on和off方法)。
  // 每一个HttpRequest对象对应一个HTTP请求。如需发起多个HTTP请求，须为每个HTTP请求创建对应HttpRequest对象。最多只能创建100个HttpRequest对象。
  let httpRequest = http.createHttp();

  // 2.订阅HTTP Response Header 事件，此接口会比request请求先返回。可以根据业务需要订阅此消息
  httpRequest.on('headersReceive', (header) => {
    Logger.info(HTTP_UTIL, 'HTTP Response Header : ' + JSON.stringify(header));
  });

  // 3.根据URL地址，发起HTTP网络请求，使用Promise方式作为异步方法。
  // request(url: string, options? : HttpRequestOptions): Promise<HttpResponse>
  let responseResult = httpRequest.request(url, {
    method: method,
    readTimeout: HTTP_READ_TIMEOUT,
    header: {
      //'Authorization': AppStorage.Get<string>(ACCESS_TOKEN_KEY),
      'Content-Type': CONTENT_TYPE_JSON
    },
    connectTimeout: HTTP_READ_TIMEOUT,
    extraData: params // 当使用POST请求时此字段用于传递内容
  });

  // 4.处理请求结果并返回
  let serverData = new HttResponseResult(); // 自定义统一请求结果包装类型
  return responseResult.then((res: http.HttpResponse) => {
    serverData.code = res.responseCode === http.ResponseCode.OK ? HttpResponseState.SUCCESS : HttpResponseState.FAIL;
    serverData.responseCode = res.responseCode;

    Logger.info(HTTP_UTIL, 'HTTP Response Result : ' + JSON.stringify(res));

    if (res.responseCode === http.ResponseCode.OK) {
      // 请求成功处理
      let result = `${res.result}`;
      serverData.data = JSON.parse(result);
    }
    if (res.responseCode === http.ResponseCode.UNAUTHORIZED || res.responseCode === http.ResponseCode.FORBIDDEN) {
      // 处理未授权或权限不足的请求
      serverData.message = `未授权的请求。`;
    }
    else {
      serverData.message = `${res.responseCode}`;
    }

    return serverData;
  }).catch((err: Error) => {
    serverData.code = HttpResponseState.FAIL;
    serverData.message = err.message;
    return serverData;
  }).finally(() => {
    // 5.当该请求使用完毕时，取消订阅header事件，并调用destroy方法主动销毁。
    httpRequest.off('headersReceive'); // 取消订阅HTTP Response Header 事件。
    httpRequest.destroy();
  });
}

/**
 * HTTP GET 请求.
 *
 * @param url URL for initiating an HTTP request.
 */
export function httpGet(url: string) {
  return httpRequest(url, http.RequestMethod.GET);
}

/**
 * HTTP POST 请求.
 *
 * @param url URL for initiating an HTTP request
 * @param newsData Additional data of the request
 * @returns
 */
export function httpPost(url: string, data: any) {
  return httpRequest(url, http.RequestMethod.POST, data);
}

export default {
  HttpResponseState,
  HttResponseResult,
  httpRequest,
  httpGet,
  httpPost
}